<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { AxiosError } from "axios";
import { ElMessage, ElMessageBox } from 'element-plus'
import type { TableInstance } from 'element-plus'
import { Folder } from '@element-plus/icons-vue'
import {
    getFiles,
    downloadFile,
    uploadFile,
    deleteFile,
    renameFile,
    createDirectory
} from '@/services/api'

const router = useRouter()
const authStore = useAuthStore()
interface FileItem {
    path: string
    name: string
    size: number
    modified: number
    directory: boolean
}

const files = ref<FileItem[]>([])
const loading = ref(false)
const currentPath = ref('/')
const tableMaxHeight = `${window.innerHeight * 0.7}`

const multipleTableRef = ref<TableInstance>()
const multipleSelection = ref<FileItem[]>([])

const handleLogout = async () => {
    await authStore.logoutUser();
    router.push('/');
}

const fetchFiles = async (path = '/') => {
    if (!path.startsWith('/')) {
        path = '/' + path;
    }
    try {
        loading.value = true
        const { data } = await getFiles(path)
        files.value = data.sort((a: FileItem, b: FileItem) => {
            if (a.directory != b.directory) {
                return a.directory ? -1 : 1
            }
            return a.name < b.name ? -1 : 1
        })
        currentPath.value = path
    } catch (error) {
        if (error instanceof AxiosError && error.response?.status === 401) {
            handleLogout();
            return;
        }
        console.error(error)
        ElMessage.error('获取文件列表失败')
    } finally {
        loading.value = false
    }
}

const handleDownload = async () => {
    let successCount = 0
    let failCount = 0

    for (const file of multipleSelection.value) {
        if (file.directory) {
            failCount++
            continue
        }

        try {
            const url = downloadFile(file.path)
            const link = document.createElement('a')
            link.href = url
            link.setAttribute('download', file.name)
            link.click()
            successCount++
            multipleTableRef.value?.toggleRowSelection(file, false)
        } catch (error) {
            console.error(error)
            failCount++
        }
    }

    if (successCount > 0) {
        ElMessage.success(`成功下载 ${successCount} 个文件`)
    }
    if (failCount > 0) {
        ElMessage.error(`${failCount} 个文件下载失败`)
    }
}

const handleDelete = async () => {
    try {
        await ElMessageBox.confirm(`确定要删除选中的 ${multipleSelection.value.length} 个文件/文件夹吗？`, '提示', {
            type: 'warning'
        })

        let successCount = 0
        let failCount = 0

        for (const file of multipleSelection.value) {
            try {
                await deleteFile(file.path)
                successCount++
                multipleTableRef.value?.toggleRowSelection(file, false)
            } catch (error) {
                console.error(error)
                failCount++
            }
        }

        if (successCount > 0) {
            ElMessage.success(`成功删除 ${successCount} 个文件/文件夹`)
            fetchFiles(currentPath.value)
        }
        if (failCount > 0) {
            ElMessage.error(`${failCount} 个文件/文件夹删除失败`)
        }
    } catch (error) {
        if (error !== 'cancel') {
            console.error(error)
        }
    }
}

const handleRename = async () => {
    const file = multipleSelection.value[0]
    try {
        const { value: newName } = await ElMessageBox.prompt('请输入新文件名', '重命名', {
            inputValue: file.name
        })
        const newPath = `${file.path.substring(0, file.path.lastIndexOf('/'))}/${newName}`
        await renameFile(file.path, newPath)
        multipleTableRef.value?.toggleRowSelection(file, false)
        ElMessage.success('重命名成功')
        fetchFiles(currentPath.value)
    } catch (error) {
        if (error !== 'cancel') {
            console.error(error)
            ElMessage.error('重命名失败')
        }
    }
}

const handleMove = async () => {
    try {
        const { value: newParentPath } = await ElMessageBox.prompt('请输入新位置', '移动', {
            inputValue: currentPath.value
        })
        let newPrefix = newParentPath;
        if (newPrefix.startsWith('/')) {
            newPrefix = newPrefix.substring(1)
        }
        if (newPrefix.endsWith('/')) {
            newPrefix = newPrefix.substring(0, newPrefix.length - 1);
        }

        let successCount = 0
        let failCount = 0

        for (const file of multipleSelection.value) {
            const newPath = (newPrefix.length == 0) ? file.name : `${newPrefix}/${file.name}`;
            if (newPath === file.path) {
                failCount++
                continue
            }

            try {
                await renameFile(file.path, newPath)
                successCount++
                multipleTableRef.value?.toggleRowSelection(file, false)
            } catch (error) {
                console.error(error)
                failCount++
            }
        }

        if (successCount > 0) {
            ElMessage.success(`成功移动 ${successCount} 个文件/文件夹`)
            fetchFiles(currentPath.value)
        }
        if (failCount > 0) {
            ElMessage.error(`${failCount} 个文件/文件夹移动失败`)
        }
    } catch (error) {
        if (error !== 'cancel') {
            console.error(error)
        }
    }
}

const handleCreateDirectory = async () => {
    try {
        const { value: dirName } = await ElMessageBox.prompt('请输入文件夹名称', '新建文件夹');
        if (dirName) {
            let dirPath = `${currentPath.value}/${dirName}`.substring(1);
            await createDirectory(dirPath);
            ElMessage.success('文件夹创建成功');
            fetchFiles(currentPath.value);
        }
    } catch (error) {
        if (error !== 'cancel') {
            console.error(error)
            ElMessage.error('文件夹创建失败');
        }
    }
};

const handleUploadSuccess = () => fetchFiles(currentPath.value);

const handleSelectionChange = (val: FileItem[]) => {
    multipleSelection.value = val
}

const showSize = (size: number) => {
    if (size < 1024) {
        return `${size}B`
    } else if (size < 1024 * 1024) {
        return `${(size / 1024).toFixed(2)}KB`
    } else if (size < 1024 * 1024 * 1024) {
        return `${(size / 1024 / 1024).toFixed(2)}MB`
    } else {
        return `${(size / 1024 / 1024 / 1024).toFixed(2)}GB`
    }
}

onMounted(() => {
    fetchFiles()
})

</script>

<template>
    <div class="file-manager">
        <div class="header">
            <el-breadcrumb separator="/">
                <el-breadcrumb-item>
                    <el-link :underline="false" @click="fetchFiles()">根目录</el-link>
                </el-breadcrumb-item>
                <el-breadcrumb-item v-for="(part, index) in currentPath.split('/').filter(Boolean)" :key="index">
                    <el-link :underline="false"
                        @click="fetchFiles(currentPath.split('/').slice(0, index + 2).join('/'))">
                        {{ part }}
                    </el-link>
                </el-breadcrumb-item>
            </el-breadcrumb>
            <div>
                <el-button type="danger" @click="handleLogout">登出</el-button>
                <el-button type="success" @click="handleCreateDirectory">新建文件夹</el-button>
            </div>
        </div>

        <div>
            <el-button type="success" :disabled="multipleSelection.length == 0" @click="handleDownload">
                下载
            </el-button>
            <el-button type="primary" :disabled="multipleSelection.length > 1 || multipleSelection.length == 0"
                @click="handleRename">
                重命名
            </el-button>
            <el-button type="warning" :disabled="multipleSelection.length == 0" @click="handleMove">
                移动
            </el-button>
            <el-button type="danger" :disabled="multipleSelection.length == 0" @click="handleDelete">
                删除
            </el-button>
        </div>

        <el-table ref="multipleTableRef" :data="files" v-loading="loading" :max-height="tableMaxHeight"
            @selection-change="handleSelectionChange" style="width: 100%; margin-top: 20px">
            <el-table-column type="selection" width="55" />
            <el-table-column prop="name" label="文件名">
                <template #default="scope">
                    <span v-if="scope.row.directory">
                        <el-icon>
                            <Folder />
                        </el-icon>
                        <el-link :style="{ fontWeight: 'bold' }" :underline="false" @click="fetchFiles(scope.row.path)">
                            {{ scope.row.name }}
                        </el-link>
                    </span>
                    <span v-else>
                        {{ scope.row.name }}
                    </span>
                </template>
            </el-table-column>
            <el-table-column prop="size" label="大小" sortable width="150">
                <template #default="scope">
                    {{ scope.row.directory ? '-' : showSize(scope.row.size) }}
                </template>
            </el-table-column>
            <el-table-column prop="modified" label="修改时间" sortable width="200">
                <template #default="scope">
                    {{ new Date(scope.row.modified).toLocaleString() }}
                </template>
            </el-table-column>
        </el-table>

        <el-upload class="upload" :action="uploadFile()" :on-success="handleUploadSuccess" multiple>
            <el-button type="primary">上传文件</el-button>
        </el-upload>
    </div>
</template>

<style scoped>
.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}

.file-manager {
    padding: 20px;
    max-width: 1300px;
}

.upload {
    margin-top: 20px;
}
</style>
